/*
 * Copyright (C) 2015-2019 Alibaba Group Holding Limited
 */

#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include "aos/kernel.h"
#include <k_api.h>
#include "aos/hal/spi.h"
#include "fsl_clock.h"
#include "fsl_lpspi.h"
#include "aos/hal/adc.h"

#define ADC_CHANNEL_NUM     8
#define ADC_SPI_PORT        3
#define ADC_DEFAULT_TIMEOUT 1000

int32_t hal_adc_init(adc_dev_t *adc)
{
    int       ret;
    spi_dev_t spi;

    if (adc == NULL) {
        return -1;
    }

    memset(&spi, 0, sizeof(spi));
    spi.port = ADC_SPI_PORT;

    ret = hal_spi_init(&spi);
    if (ret != 0) {
        return -1;
    }

    return 0;
}


/**@biref Takes a single sample from an ADC interface
 *
 * Takes a single sample from an ADC interface
 *
 * @param  adc      : the interface which should be sampled
 * @param  output   : pointer to a variable which will receive the sample
 * @param  timeout  : ms timeout
 * @return 0        : on success.
 * @return EIO      : if an error occurred with any step
 */
int32_t hal_adc_value_get(adc_dev_t *adc, void *output, uint32_t timeout)
{
    int ret;
    uint16_t adc_value;
    uint8_t data_in[3];
    uint8_t data_out[3];
    spi_dev_t spi;

    if (adc == NULL) {
        return -1;
    }

    if (adc->port >= ADC_CHANNEL_NUM) {
        return -1;
    }

    if (output == NULL) {
        return -1;
    }

    if (timeout == 0) {
        timeout = ADC_DEFAULT_TIMEOUT;
    }

    data_in[0] = (uint8_t)(0);
    data_in[1] = (uint8_t)(0);
    data_in[2] = (uint8_t)(0xc0 | ((adc->port & 0x7) << 3));
    memset(data_out, 0, sizeof(data_out));

    memset(&spi, 0, sizeof(spi));
    spi.port = ADC_SPI_PORT;

    ret = hal_spi_send_recv(&spi, &data_in[0], &data_out[0], 3, timeout);
    if (ret != 0) {
        return -1;
    }

    adc_value = ((data_out[2] & 0x1) << 11) |
                (data_out[1] << 3) |
                (data_out[0] >> 5);

    *(uint16_t*)output = adc_value;

    return 0;
}


/**@biref     De-initialises an ADC interface
 *
 * @abstract Turns off an ADC hardware interface
 *
 * @param  adc : the interface which should be de-initialised
 *
 * @return 0   : on success.
 * @return EIO : if an error occurred with any step
 */
int32_t hal_adc_finalize(adc_dev_t *adc)
{
    int ret;
    spi_dev_t spi;

    if (adc == NULL) {
        return -1;
    }

    memset(&spi, 0, sizeof(spi));

    spi.port = ADC_SPI_PORT;

    ret = hal_spi_finalize(&spi);
    if (ret != 0) {
        return -1;
    }

    return 0;
}

